<template>
  <div>
    <!-- h264视频格式 -->
    <div v-if="isHls" class="video-container" v-show="status === 'success'">
      <video
        :ref="`videoRef${videoObject.id}`"
        :src="videoObject.src"
        autoplay
        muted
        v-if="videoObject.src"
      >
        <!-- 添加字幕文件 -->
        <track kind="subtitles" srclang="zh" label="中文" />
      </video>
      <div class="video-tips" v-else>暂无视频</div>
    </div>
    <!-- flv视频格式 -->
    <div v-else class="video-container" v-show="status === 'success'">
      <video :ref="`videoRef${videoObject.id}`" autoplay muted></video>
    </div>
    <!-- 加载中、加载失败提示 -->
    <div class="video-tips" v-show="status === 'loading'">视频加载中...</div>
    <div class="video-tips" v-show="status === 'error'">
      视频加载失败，点击
      <span class="span-btn" @click="reconnect">刷新</span>
    </div>
  </div>
</template>

<script>
import { debounce } from '@/utils/tools';
import Flvjs from 'flv.js';
import Hlsjs from 'hls.js';
import { VIDEO_STATUS } from '../js/index';
export default {
  name: 'VideoBlock',
  data() {
    return {
      // hls对象
      hlsjs: null,
      // 状态
      status: VIDEO_STATUS.loading,
      // flv对象
      flvjs: null,
    };
  },
  props: {
    videoObject: {
      type: Object,
      default: () => {
        return {
          id: null,
          src: null,
        };
      },
    },
  },
  computed: {
    // 展示hls
    isHls() {
      return (
        this.videoObject.src.endsWith('.m3u8') ||
        this.videoObject.src.endsWith('.mp4')
      );
    },
    // 当前的video元素
    currentVideoEl() {
      return this.$refs[`videoRef${this.videoObject.id}`];
    },
  },
  beforeDestroy() {
    // 销毁 Hlsjs 实例
    if (this.hlsjs) {
      this.hlsjs.destroy();
    }
    if (this.flvjs) {
      this.flvjs.destroy();
    }
  },
  watch: {
    videoObject: {
      handler() {
        debounce(this.playVideo(), 500);
      },
      deep: true,
      immediate: true,
    },
  },
  methods: {
    /**
     * 播放视频
     */
    playVideo() {
      this.status = VIDEO_STATUS.loading;
      this.$nextTick(() => {
        // 检查 videoObject 是否有效
        if (
          !this.videoObject ||
          !this.videoObject.id ||
          !this.videoObject.src
        ) {
          console.error('Invalid videoObject:', this.videoObject);
          return;
        }
        // 检查当前video元素是否有效
        if (
          !this.currentVideoEl ||
          !(this.currentVideoEl instanceof HTMLVideoElement)
        ) {
          console.error('Invalid video element:', this.currentVideoEl);
          this.status = VIDEO_STATUS.error;
          return;
        }
        this.isHls ? this.hlsPlay() : this.flvPlay();
      });
    },
    /**
     * hls播放
     */
    hlsPlay() {
      this.currentVideoEl.load();
      // 检查视频格式并选择播放方式
      if (this.videoObject.src.endsWith('.m3u8')) {
        console.log('Playing M3U8 file');
        if (Hlsjs.isSupported()) {
          this.hlsjs = new Hlsjs();
          this.hlsjs.loadSource(this.videoObject.src);
          this.hlsjs.attachMedia(this.currentVideoEl);
          // 缓冲策略
          this.hlsjs.config.maxBufferLength = 60;
          this.hlsjs.config.minBufferLength = 5;
          this.hlsjs.config.maxBufferSize = 10 * 1024 * 1024;
          this.hlsjs.config.autoLevelCapping = -1; // 自动选择最佳码率
          this.hlsjs.config.capLevelOnFPSDrop = true; // 当帧率下降时降低码率
          this.hlsjs.config.capLevelToPlayerSize = true; // 根据播放器尺寸调整码率
          // 网络错误重试
          this.hlsjs.config.retry = {
            retries: 5,
            backoff: 'exponential',
            maxRetryDelay: 5,
          };
          this.hlsjs.on(Hlsjs.Events.LEVEL_SWITCHED, () => {
            this.hlsjs.startLoad();
          });
          this.hlsjs.on(Hlsjs.Events.MANIFEST_PARSED, () => {
            this.currentVideoEl.play().catch((error) => {
              console.error('Video play error:', error);
              this.status = VIDEO_STATUS.error;
            });
            console.log('HLS play started');
            this.status = VIDEO_STATUS.success;
          });
          // 监听缓冲事件
          this.hlsjs.on(Hlsjs.Events.BUFFER_APPENDING, (event, data) => {
            return event, data;
          });
          // 监听缓冲卡顿事件
          this.hlsjs.on(Hlsjs.Events.BUFFER_STALLED, () => {
            console.warn('Buffer stalled, attempting to recover...');
            this.hlsjs.recoverMediaError(); // 尝试恢复媒体错误
          });
          // 监听缓冲区满事件
          this.hlsjs.on(Hlsjs.Events.BUFFER_FULL, () => {
            console.warn('Buffer is full, attempting to free space...');
            this.hlsjs.bufferController.removeBufferRange(
              0,
              this.hlsjs.bufferController.getBufferedRangeEnd(0) - 10
            ); // 清理部分缓冲区
          });
          this.hlsjs.on(Hlsjs.Events.ERROR, (event, data) => {
            console.error(event, data);
            this.status = VIDEO_STATUS.error;
            return;
          });
        } else {
          this.status = VIDEO_STATUS.error;
          return;
        }
      } else if (this.videoObject.src.endsWith('.mp4')) {
        console.log('Playing MP4 file');
        this.hlsjs = new Hlsjs();
        // this.currentVideoEl.src = this.videoObject.src;
        this.currentVideoEl.addEventListener('loadedmetadata', () => {
          this.currentVideoEl
            .play()
            .then(() => {
              this.status = VIDEO_STATUS.success;
            })
            .catch((error) => {
              console.error('Video play error:', error);
              this.status = VIDEO_STATUS.error;
            });
        });
        // 添加视频元素的错误事件监听器
        this.currentVideoEl.addEventListener('error', (event) => {
          console.error('Video element error:', event);
          this.status = VIDEO_STATUS.error;
        });
      } else {
        this.$message.error('不支持的格式');
        this.status = VIDEO_STATUS.error;
        return;
      }
    },
    /**
     * flv播放
     */
    flvPlay() {
      console.log('Playing FLV file');
      if (Flvjs.isSupported()) {
        this.flvjs = Flvjs.createPlayer(
          {
            type: 'flv',
            hasAudio: false,
            url: this.videoObject.src,
          }
          //   {
          //   type: 'flv',
          //   url: this.videoObject.src,
          //   isLive: true,
          //   hasAudio: false,
          //   cors: true,
          //   enableWorker: true,
          //   enableStashBuffer: false,
          //   // 关闭懒加载以加快加载速度
          //   lazyLoad: false,
          //   // 设置合理的最大缓存时长
          //   lazyLoadMaxDuration: 60, // 1分钟
          //   seekType: 'range', // 如果需要支持Range请求，保留此配置
          //   rangeLoadZeroStart: true, // 支持Range请求
          //   rangeLoadMaxDuration: 60 * 60 * 24, // 24小时
          // }
        );
        this.flvjs.attachMediaElement(this.currentVideoEl);
        this.flvjs.load();
        // 添加 canplay 事件监听
        this.currentVideoEl.addEventListener('canplay', () => {
          this.flvjs.play().catch((error) => {
            console.error('Video play error:', error);
            this.status = VIDEO_STATUS.error;
          });
          this.status = VIDEO_STATUS.success;
        });
        // 添加 error 事件监听
        this.currentVideoEl.addEventListener('error', (event) => {
          console.error('Video play error:', event);
          this.status = VIDEO_STATUS.error;
        });

        // 添加 flv.js 自身的错误事件监听
        this.flvjs.on(Flvjs.Events.ERROR, (event, data) => {
          console.error('FLV.js error:', event, data);
          this.status = VIDEO_STATUS.error;
        });
      } else {
        this.$message.error('不支持的格式');
        this.status = VIDEO_STATUS.error;
        return;
      }
    },
    /**
     * 重新连接
     */
    reconnect() {
      console.log('Reconnecting...');
      this.status = VIDEO_STATUS.loading;
      if (this.flvjs) {
        this.flvjs.destroy();
        this.flvjs = null;
        this.flvPlay();
      } else if (this.hlsjs) {
        this.hlsjs.destroy();
        this.hlsjs = null;
        this.hlsPlay();
      }
    },
  },
};
</script>

<style scoped lang="scss">
.video-container,
video {
  width: 100%;
  height: 100%;
  box-sizing: border-box;
  object-fit: cover; /* 视频填充方式 */
}
.video-tips {
  width: 100%;
  height: 100%;
  background-color: #000;
  display: flex;
  align-items: center;
  justify-content: center;
  color: #fff;
  font-size: 20px;
  font-weight: bold;
}
.span-btn {
  margin-left: 5px;
  color: #409eff;
  text-decoration: underline;
  cursor: pointer;
}
</style>
